﻿using System.Runtime.InteropServices;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;

namespace Bread.Mvc.Avalonia;

/// <summary>
/// 移动窗体, 仅支持Windows系统 <br/>
/// 优先在鼠标按下的事件中调用 Window.BeginMoveDrag
/// </summary>
public class DragMoveHelper
{
    Control _target;
    Window? _host;
    nint _hwnd;

    public DragMoveHelper(Control ctr, nint hwnd)
    {
        _hwnd = hwnd;
        _target = ctr;

        var top = TopLevel.GetTopLevel(_target);
        if (top is Window w && w != null) {
            _host = w;
        }

        _target.PointerPressed += _target_PointerPressed;
        _target.PointerMoved += _target_PointerMoved;
        _target.PointerReleased += _target_PointerReleased;
    }

    bool _isDragging = false;
    bool _isLeftButtonDown = false;

    PixelPoint _downPoint;
    PixelPoint _downPosition;

    private void _target_PointerPressed(object? sender, PointerPressedEventArgs e)
    {
        if (_host == null) return;
        if (e.GetCurrentPoint(_target).Properties.IsLeftButtonPressed == false) return;
        _isLeftButtonDown = true;
        e.Pointer.Capture(_target);
    }


    private void _target_PointerMoved(object? sender, PointerEventArgs e)
    {
        if (_host == null) return;
        if (_isLeftButtonDown == false) return;

        if (_isDragging == false) {
            _isDragging = true;

            _downPoint = _host.PointToScreen(e.GetPosition(_host));

            var rect = new NativeMethods.RECT();
            NativeMethods.GetWindowRect(_hwnd, ref rect);
            _downPosition = new PixelPoint(rect.Left, rect.Top);

            return;
        }

        var pt = _host.PointToScreen(e.GetPosition(_host));
        var newPt = _downPosition + pt - _downPoint;

        NativeMethods.SetWindowPos(_hwnd, nint.Zero, newPt.X, newPt.Y, 0, 0,
            NativeMethods.SWP_NOACTIVATE | NativeMethods.SWP_NOSIZE |
            NativeMethods.SWP_NOZORDER | NativeMethods.SWP_NOOWNERZORDER);

        e.Handled = true;
    }

    private void _target_PointerReleased(object? sender, PointerReleasedEventArgs e)
    {
        _isLeftButtonDown = false;
        _isDragging = false;

        if (e.Pointer.Captured == _target) {
            e.Pointer.Capture(null);
        }
    }


    private static class NativeMethods
    {

        // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowpos
        public const int SWP_NOMOVE = 0x0002;
        public const int SWP_NOSIZE = 0x0001;
        public const int SWP_NOZORDER = 0x0004;
        public const int SWP_NOACTIVATE = 0x0010;
        public const int SWP_NOOWNERZORDER = 0x0200;

        public struct RECT
        {
            public int Left;        // x position of upper-left corner
            public int Top;         // y position of upper-left corner
            public int Right;       // x position of lower-right corner
            public int Bottom;      // y position of lower-right corner
        }


        [DllImport("user32.dll")]
        public static extern bool GetWindowRect(IntPtr hwnd, ref RECT rectangle);


        [DllImport("User32.dll", SetLastError = true)]
        public static extern bool SetWindowPos(nint hWnd, nint hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
    }


}


public static class DragMoveExtension
{
    public static void AttachDragMove(this Control v)
    {
        v.PointerPressed += (s, e) => {
            if (e.GetCurrentPoint(v).Properties.IsLeftButtonPressed == false) return;
            var top = TopLevel.GetTopLevel(v);
            if (top is Window w && w != null) {
                w.BeginMoveDrag(e);
            }
        };
    }
}

